package com.pctx.pay.wxpay.controller;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.pctx.pay.order.pojo.SystemOrder;
import com.pctx.pay.order.service.SystemOrderService;
import com.pctx.wxpay.sdk.WXPay;
import com.pctx.wxpay.sdk.WXPayConfigImpl;
import com.pctx.wxpay.sdk.WXPayConstants;
import com.pctx.wxpay.sdk.WXPayUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@RestController
@RequestMapping("wxpay")
public class WeiXinController {

    private Logger logger = Logger.getLogger(this.getClass());
    @Autowired
    private SystemOrderService systemOrderService;
    @Autowired
    RestTemplate restTemplate;

    /**
     * 创建微信扫码支付
     *
     * @return
     * @throws Exception
     */
    @PostMapping("/order/scan")
    public Map<String, String> createScanPayOrder(SystemOrder systemOrder, HttpServletRequest request,
                                                  HttpServletResponse response) throws Exception {
        if (StringUtils.isNotEmpty(systemOrder.getIp())) {
            systemOrder.setIp("127.0.0.1");
        }
        systemOrder.setWay("PC");
        systemOrder.setPay_way("wxpay");
        // 创建系统订单
        systemOrderService.createSystemOrder(systemOrder);

        BigDecimal b1 = new BigDecimal(Double.toString(systemOrder.getPay_money())).setScale(2, RoundingMode.UP);
        BigDecimal b2 = new BigDecimal(Double.toString(100));
        Integer totalFee = b1.multiply(b2).intValue();

        WXPayConfigImpl config = WXPayConfigImpl.getInstance();
        WXPay wxpay = new WXPay(config);

        Map<String, String> data = new HashMap<String, String>();
        data.put("body", systemOrder.getSubject());
        data.put("out_trade_no", systemOrder.getOrderno());
        data.put("device_info", "");
        data.put("fee_type", "CNY");
        data.put("total_fee", totalFee.toString());
        data.put("spbill_create_ip", systemOrder.getIp());
        data.put("notify_url", WXPayConstants.PAY_NOTIFY_URL);
        data.put("trade_type", "NATIVE");
        // data.put("product_id", "12");
        // data.put("time_expire", "20170112104120");
        Map<String, String> map = wxpay.unifiedOrder(data);
        return map;
    }

    /**
     * 创建微信扫码支付，返回二维码的二进制流
     *
     * @return
     * @throws Exception
     */
    @PostMapping("/order/scan.jpg")
    public void createScanPayOrderJpg(SystemOrder systemOrder, HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
        Map<String, String> map = createScanPayOrder(systemOrder, request, response);
        String url = (String) map.get("code_url");
        // 将微信接口返回的链接生成二维码，二维码支付的有效期为2小时，过期后无法支付
        if (StringUtils.isNotEmpty(url)) {
            Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
            hints.put(EncodeHintType.MARGIN, 0);
            BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, 260, 260, hints);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) == true ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
                }
            }
            ImageIO.write(image, "jpg", response.getOutputStream());
        }
    }

    /**
     * 创建微信公众号JSAPI支付
     *
     * @return
     * @throws Exception
     */
    @PostMapping("order/jsapi")
    public Map<String, String> createJSAPIPayOrder(SystemOrder systemOrder, HttpServletRequest req,
                                                   HttpServletResponse resp) throws Exception {
        if (StringUtils.isNotEmpty(systemOrder.getIp())) {
            systemOrder.setIp("127.0.0.1");
        }
        systemOrder.setWay("PC");
        systemOrder.setPay_way("JSSDK");
        // 创建系统订单
        systemOrderService.createSystemOrder(systemOrder);

        BigDecimal b1 = new BigDecimal(Double.toString(systemOrder.getPay_money())).setScale(2, RoundingMode.UP);
        BigDecimal b2 = new BigDecimal(Double.toString(100));
        Integer totalFee = b1.multiply(b2).intValue();

        WXPayConfigImpl config = WXPayConfigImpl.getInstance();
        WXPay wxpay = new WXPay(config);

        Map<String, String> data = new HashMap<String, String>();
        data.put("body", systemOrder.getSubject());
        data.put("out_trade_no", systemOrder.getOrderno());
        data.put("openid", systemOrder.getOpenid());
        data.put("device_info", "");
        data.put("fee_type", "CNY");
        data.put("total_fee", totalFee.toString());
        data.put("spbill_create_ip", systemOrder.getIp());
        data.put("notify_url", WXPayConstants.PAY_NOTIFY_URL);
        data.put("trade_type", "JSAPI");
        // data.put("product_id", "12");
        // data.put("time_expire", "20170112104120");
        Map<String, String> map = wxpay.unifiedOrder(data);

        Map<String, String> payMap = new HashMap<String, String>();
        payMap.put("appId", map.get("appid"));
        payMap.put("timeStamp", create_timestamp());
        payMap.put("nonceStr", map.get("nonce_str"));
        payMap.put("signType", "MD5");
        // 预付商品id
        payMap.put("package", "prepay_id=" + map.get("prepay_id"));
        payMap.put("pg", map.get("prepay_id"));
        payMap.put("paySign", map.get("sign"));
        return payMap;
    }

    /**
     * 微信支付回调
     *
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/notify")
    public String notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("微信公众号支付回调开始");
        // 读取参数
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream = request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        while ((s = in.readLine()) != null) {
            sb.append(s);
        }
        in.close();
        inputStream.close();
        logger.info("微信公众号支付回调的参数：" + sb.toString());
        // 解析xml成map
        Map<String, String> m = WXPayUtil.xmlToMap(sb.toString());

        // 过滤空 设置 TreeMap
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        Iterator it = m.keySet().iterator();
        while (it.hasNext()) {
            String parameter = (String) it.next();
            String parameterValue = m.get(parameter);

            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            packageParams.put(parameter, v);
        }

        // 处理业务开始
        String resXml = "";
        if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
            // //////// 执行业务逻辑////////////////
            String appid = (String) packageParams.get("appid");
            // String mch_id = (String) packageParams.get("mch_id");
            String openid = (String) packageParams.get("openid");
            // String is_subscribe = (String)
            // packageParams.get("is_subscribe"); // 是否订阅
            String out_trade_no = (String) packageParams.get("out_trade_no"); // 订单
            String transaction_id = (String) packageParams.get("transaction_id"); // 微信回调订单号
            // String total_fee = (String) packageParams.get("total_fee");
            // // 价格
            // System.out.println("支付成功");
            // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
            resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml> ";
            // 处理支付订单
            if (null != out_trade_no) {
                logger.info("微信支付回调订单号：" + out_trade_no);

                SystemOrder systemOrder = new SystemOrder();
                systemOrder.setOrderno(out_trade_no);
                systemOrder = systemOrderService.querySystemOrder(systemOrder);
                // 修改订单状态为成功
                if (null != systemOrder && 1 == systemOrder.getStatus()) {
                    systemOrder.setStatus(1);
                    systemOrder.setAppid(appid);
                    systemOrder.setOpenid(openid);
                    systemOrder.setPay_trade_no(transaction_id);
                    systemOrder.setPay_time(new Date());
                    systemOrderService.updateSystemOrder(systemOrder);

                    // 调用支付后回调的微服务
                    String notify_url = systemOrder.getNotify_url();
                    restTemplate.postForEntity(notify_url, systemOrder, String.class);
                }
            }
        } else {
            logger.error("支付失败,错误信息：" + packageParams.get("err_code"));
            resXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
        }
        // 处理业务完毕
        return resXml;
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

}